home *** CD-ROM | disk | FTP | other *** search
/ Collection of Tools & Utilities / Collection of Tools and Utilities.iso / edit / elv18src.zip / cut.c < prev    next >
C/C++ Source or Header  |  1994-01-02  |  16KB  |  777 lines

  1. /* cut.c */
  2.  
  3. /* Author:
  4.  *    Steve Kirkendall
  5.  *    14407 SW Teal Blvd. #C
  6.  *    Beaverton, OR 97005
  7.  *    kirkenda@cs.pdx.edu
  8.  */
  9.  
  10.  
  11. /* This file contains function which manipulate the cut buffers. */
  12.  
  13. #include "config.h"
  14. #include "vi.h"
  15. #if TURBOC
  16. #include <process.h>        /* needed for getpid */
  17. #endif
  18. #if TOS
  19. #include <osbind.h>
  20. #define    rename(a,b)    Frename(0,a,b)
  21. #endif
  22.  
  23. # define NANONS    9    /* number of anonymous buffers */
  24.  
  25. static struct cutbuf
  26. {
  27.     short    *phys;    /* pointer to an array of #s of BLKs containing text */
  28.     int    nblks;    /* number of blocks in phys[] array */
  29.     int    start;    /* offset into first block of start of cut */
  30.     int    end;    /* offset into last block of end of cut */
  31.     int    tmpnum;    /* ID number of the temp file */
  32.     char    lnmode;    /* boolean: line-mode cut? (as opposed to char-mode) */
  33. }
  34.     named[27],    /* cut buffers "a through "z and ". */
  35.     anon[NANONS];    /* anonymous cut buffers */
  36.  
  37. static char    cbname;    /* name chosen for next cut/paste operation */
  38. static char    dotcb;    /* cut buffer to use if "doingdot" is set */
  39.  
  40.  
  41. #ifndef NO_RECYCLE
  42. /* This function builds a list of all blocks needed in the current tmp file
  43.  * for the contents of cut buffers.
  44.  * !!! WARNING: if you have more than ~450000 bytes of text in all of the
  45.  * cut buffers, then this will fail disastrously, because buffer overflow
  46.  * is *not* allowed for.
  47.  */
  48. int cutneeds(need)
  49.     BLK        *need;    /* this is where we deposit the list */
  50. {
  51.     struct cutbuf    *cb;    /* used to count through cut buffers */
  52.     int        i;    /* used to count through blocks of a cut buffer */
  53.     int        n;    /* total number of blocks in list */
  54.  
  55.     n = 0;
  56.  
  57.     /* first the named buffers... */
  58.     for (cb = named; cb < &named[27]; cb++)
  59.     {
  60.         if (cb->tmpnum != tmpnum)
  61.             continue;
  62.  
  63.         for (i = cb->nblks; i-- > 0; )
  64.         {
  65.             need->n[n++] = cb->phys[i];
  66.         }
  67.     }
  68.  
  69.     /* then the anonymous buffers */
  70.     for (cb = anon; cb < &anon[NANONS]; cb++)
  71.     {
  72.         if (cb->tmpnum != tmpnum)
  73.             continue;
  74.  
  75.         for (i = cb->nblks; i-- > 0; )
  76.         {
  77.             need->n[n++] = cb->phys[i];
  78.         }
  79.     }
  80.  
  81.     /* return the length of the list */
  82.     return n;
  83. }
  84. #endif
  85.  
  86. static void maybezap(num)
  87.     int    num;    /* the tmpnum of the temporary file to [maybe] delete */
  88. {
  89.     char    cutfname[80];
  90.     int    i;
  91.  
  92.     /* if this is the current tmp file, then we'd better keep it! */
  93.     if (tmpfd >= 0 && num == tmpnum)
  94.     {
  95.         return;
  96.     }
  97.  
  98.     /* see if anybody else needs this tmp file */
  99.     for (i = 27; --i >= 0; )
  100.     {
  101.         if (named[i].nblks > 0 && named[i].tmpnum == num)
  102.         {
  103.             break;
  104.         }
  105.     }
  106.     if (i < 0)
  107.     {
  108.         for (i = NANONS; --i >= 0 ; )
  109.         {
  110.             if (anon[i].nblks > 0 && anon[i].tmpnum == num)
  111.             {
  112.                 break;
  113.             }
  114.         }
  115.     }
  116.  
  117.     /* if nobody else needs it, then discard the tmp file */
  118.     if (i < 0)
  119.     {
  120. #if MSDOS || TOS || OS2
  121.         strcpy(cutfname, o_directory);
  122.         if ((i = strlen(cutfname)) && !strchr(":/\\", cutfname[i - 1]))
  123.             cutfname[i++] = SLASH;
  124.         sprintf(cutfname + i, TMPNAME + 3, getpid(), num);
  125. #else
  126.         sprintf(cutfname, TMPNAME, o_directory, getpid(), num);
  127. #endif
  128.         unlink(cutfname);
  129.     }
  130. }
  131.  
  132. /* This function frees a cut buffer.  If it was the last cut buffer that
  133.  * refered to an old temp file, then it will delete the temp file. */
  134. static void cutfree(buf)
  135.     struct cutbuf    *buf;
  136. {
  137.     int    num;
  138.  
  139.     /* return immediately if the buffer is already empty */
  140.     if (buf->nblks <= 0)
  141.     {
  142.         return;
  143.     }
  144.  
  145.     /* else free up stuff */
  146.     num = buf->tmpnum;
  147.     buf->nblks = 0;
  148. #ifdef DEBUG
  149.     if (!buf->phys)
  150.         msg("cutfree() tried to free a NULL buf->phys pointer.");
  151.     else
  152. #endif
  153.     _free_((char *)buf->phys);
  154.  
  155.     /* maybe delete the temp file */
  156.     maybezap(num);
  157. }
  158.  
  159. /* This function is called when we are about to abort a tmp file.
  160.  *
  161.  * To minimize the number of extra files lying around, only named cut buffers
  162.  * are preserved in a file switch; the anonymous buffers just go away.
  163.  */
  164. void cutswitch()
  165. {
  166.     int    i;
  167.  
  168.     /* mark the current temp file as being "obsolete", and close it.  */
  169.     storename((char *)0);
  170.     close(tmpfd);
  171.     tmpfd = -1;
  172.  
  173.     /* discard all anonymous cut buffers */
  174.     for (i = 0; i < NANONS; i++)
  175.     {
  176.         cutfree(&anon[i]);
  177.     }
  178.  
  179.     /* delete the temp file, if we don't really need it */
  180.     maybezap(tmpnum);
  181. }
  182.  
  183. /* This function should be called just before termination of vi */
  184. void cutend()
  185. {
  186.     int    i;
  187.  
  188.     /* free the anonymous buffers, if they aren't already free */
  189.     cutswitch();
  190.  
  191.     /* free all named cut buffers, since they might be forcing an older
  192.      * tmp file to be retained.
  193.      */
  194.     for (i = 0; i < 27; i++)
  195.     {
  196.         cutfree(&named[i]);
  197.     }
  198.  
  199.     /* delete the temp file */
  200.     maybezap(tmpnum);
  201. }
  202.  
  203.  
  204. /* This function is used to select the cut buffer to be used next */
  205. void cutname(name)
  206.     int    name;    /* a single character */
  207. {
  208.     cbname = name;
  209. }
  210.  
  211.  
  212. #ifndef NO_LEARN
  213. /* This function appends a single character to a cut buffer; it is used
  214.  * during "learn" mode to record a keystroke.  The buffer to use is determined
  215.  * by an external variable, `learnbuf'; this variable contains the buffer's
  216.  * name while learning, or '\0' if not learning.
  217.  */
  218. void learnkey(key)
  219.     char        key;    /* keystroke to append to learning buffer */
  220. {
  221.     static char    prevlearn;    /* previously learned buffer name */
  222.     static char    buf[BLKSIZE];    /* used for storing keystrokes */
  223.     static int    nkeys;        /* number of keystrokes in buf[] */
  224.     struct cutbuf    *cb;        /* ptr to buffer being saved */
  225.     long        seekpos;    /* where saved cutbuf's text goes */
  226.  
  227.     /* if we're ending a learn operation, then save keystokes in a cutbuf */
  228.     if (learn != prevlearn && prevlearn)
  229.     {
  230.         /* choose the cutbuffer to use; free its old contents, if any */
  231.         cb = &named[prevlearn - 'a'];
  232.         cutfree(cb);
  233.  
  234.         /* delete the final "]a" (or whatever) from the keystoke buffer */
  235.         nkeys -= 2;
  236.  
  237.         /* allocate a BLK for storage of the keystrokes */
  238.         cb->phys = (short *)malloc(sizeof(short));
  239.         cb->nblks = 1;
  240.         cb->start = 0;
  241.         cb->end = nkeys;
  242.         cb->tmpnum = tmpnum;
  243. #ifndef NO_RECYCLE
  244.         seekpos = allocate();
  245.         lseek(tmpfd, seekpos, 0);
  246. #else
  247.         seekpos = lseek(tmpfd, 0L, 2);
  248. #endif
  249.         cb->phys[0] = (short)(seekpos / BLKSIZE);
  250.  
  251.         /* write the keystokes there */
  252.         if (write(tmpfd, buf, (unsigned)BLKSIZE) != BLKSIZE)
  253.         {
  254.             msg("Trouble writing to tmp file");
  255.             deathtrap(0);
  256.         }
  257.  
  258.         /* saving complete */
  259.         prevlearn = '\0';
  260.         nkeys = 0;
  261.     }
  262.  
  263.     /* if we're learning a buffer now, save the keystroke */
  264.     if (learn)
  265.     {
  266.         prevlearn = learn;
  267.         buf[nkeys++] = key;
  268.         if (nkeys >= BLKSIZE - 2)
  269.         {
  270.             msg("Learn buffer full");
  271.             learn = 0;
  272.             nkeys += 2; /* <- to fake "]a" in keystroke buffer */
  273.         }
  274.     }
  275. }
  276. #endif /* !NO_LEARN */
  277.  
  278.  
  279.  
  280. /* This function copies a selected segment of text to a cut buffer */
  281. void cut(from, to)
  282.     MARK    from;        /* start of text to cut */
  283.     MARK    to;        /* end of text to cut */
  284. {
  285.     int        first;    /* logical number of first block in cut */
  286.     int        last;    /* logical number of last block used in cut */
  287.     long        line;    /* a line number */
  288.     int        lnmode;    /* boolean: will this be a line-mode cut? */
  289.     MARK        delthru;/* end of text temporarily inserted for apnd */
  290.     REG struct cutbuf *cb;
  291.     REG long    l;
  292.     REG int        i;
  293.     REG char    *scan;
  294.     char        *blkc;
  295.  
  296.     /* detect whether this must be a line-mode cut or char-mode cut */
  297.     if (markidx(from) == 0 && markidx(to) == 0)
  298.         lnmode = TRUE;
  299.     else
  300.         lnmode = FALSE;
  301.  
  302.     /* by default, we don't "delthru" anything */
  303.     delthru = MARK_UNSET;
  304.  
  305.     /* handle the "doingdot" quirks */
  306.     if (doingdot)
  307.     {
  308.         if (!cbname)
  309.         {
  310.             cbname = dotcb;
  311.         }
  312.     }
  313.     else if (cbname != '.')
  314.     {
  315.         dotcb = cbname;
  316.     }
  317.  
  318.     /* decide which cut buffer to use */
  319.     if (!cbname)
  320.     {
  321.         /* free up the last anonymous cut buffer */
  322.         cutfree(&anon[NANONS - 1]);
  323.  
  324.         /* shift the anonymous cut buffers */
  325.         for (i = NANONS - 1; i > 0; i--)
  326.         {
  327.             anon[i] = anon[i - 1];
  328.         }
  329.  
  330.         /* use the first anonymous cut buffer */
  331.         cb = anon;
  332.         cb->nblks = 0;
  333.     }
  334.     else if (cbname >= 'a' && cbname <= 'z')
  335.     {
  336.         cb = &named[cbname - 'a'];
  337.         cutfree(cb);
  338.     }
  339. #ifndef CRUNCH
  340.     else if (cbname >= 'A' && cbname <= 'Z')
  341.     {
  342.         cb = &named[cbname - 'A'];
  343.         if (cb->nblks > 0)
  344.         {
  345.             /* resolve linemode/charmode differences */
  346.             if (!lnmode && cb->lnmode)
  347.             {
  348.                 from &= ~(BLKSIZE - 1);
  349.                 if (markidx(to) != 0 || to == from)
  350.                 {
  351.                     to = to + BLKSIZE - markidx(to);
  352.                 }
  353.                 lnmode = TRUE;
  354.             }
  355.  
  356.             /* insert the old cut-buffer before the new text */
  357.             mark[28] = to;
  358.             delthru = paste(from, FALSE, TRUE);
  359.             if (delthru == MARK_UNSET)
  360.             {
  361.                 return;
  362.             }
  363.             delthru++;
  364.             to = mark[28];
  365.         }
  366.